﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;

using PriceLibrary.PriceService;

using VDataAdapter.BlockingQueue;

namespace VDataAdapter.Communication
{
    public class VDataCommunicatorException
    {

    }

    /// <summary>
    /// This class send objects to queue
    /// include a flag checker to check the sequence
    /// All data send to Vdata queue should use this class
    /// all Send method is atomic
    /// </summary>
    public class VDataCommunicator
    {
        protected readonly ILog _log = LogManager.GetLogger(typeof(VDataCommunicator));

        VdataFlagChecker _checker;

        ProtocolMessageBuilder _builder;

        protected CommunicationDataQueue _queue;

        private Object _builderLock = new Object();

        public DataSource DataSource
        {
            get { return _dataSource; }
        }
        DataSource _dataSource;

        public VDataCommunicator(DataSource dataSource, CommunicationDataQueue queue)        
        {
            _queue = queue;          
            
            IVdataMessageBuilder msgBuilder = new VDataMessageBuilder(dataSource.BasePrices);
            _dataSource = dataSource;
            _builder = new ProtocolMessageBuilder(msgBuilder, dataSource);
            _checker = new VdataFlagChecker();
        }

        public void UpdateBasePrices(IDictionary<string, PriceLibrary.PriceService.StockBase> basePrices)
        {
            _builder.UpdateBasePrices(basePrices);
        }

        /// <summary>
        /// send 1 transaction, if it is already in the DataSource then send the new along with the old
        /// it should be blocking too since many thread may want to update DataSource
        /// </summary>
        /// <param name="transaction"></param>        
        public void SendTransactionPutThrough(PriceLibrary.PriceService.Transaction transaction)
        {
            lock (this)
            {
                string msg;

                msg = _builder.BuildMessageTransactionPutThrough(transaction);

                SendToQueue(msg, _queue);
            }
        }

        public void SendTransaction(PriceLibrary.ChartService.Transaction transaction)
        {
            string msg;
            // if DataSource already contain this Transaction, send new transaction along with the old
            msg = _builder.BuildMessageTransaction(transaction);

            // send the message
            SendToQueue(msg, _queue);  
        }

        public void SendFlag(MessageFlagSequeue flag)
        { 
            string flagMsg = VDataFlag.GetFlag(flag);
            _checker.CheckFlag(flagMsg);
            SendToQueue(flagMsg, _queue);
            
        }

        public void SendMarketInfo(int key, PriceLibrary.PriceService.MarketInfo marketInfo)
        {
            string msg;

            msg = _builder.BuildMessageMarketInfo(key, marketInfo);

            try
            {
                SendToQueue(msg, _queue);
            }
            catch (Exception ex)
            {
                throw new Exception("Cant send to queue: " + ex.Message, ex);
            }
        }

        public void SendStock(string key, StockInfoDyns dynamicInfo)
        {
            string msg;

            msg = _builder.BuildMessageStockInfo(key, dynamicInfo);

            SendToQueue(msg, _queue);
        }

        private void SendPutThrough(StockInfoDyns putThrough)
        {
            string msg;

            msg = _builder.BuildMessagePutThroughTopPrices(putThrough.StockSymbol, putThrough);

            SendToQueue(msg, _queue);
        }

        /// <summary>
        /// Send a list of PutThrough StockInfoDyns
        /// </summary>
        /// <param name="newstockbase"></param>
        public void SendPutThrough(IList<StockInfoDyns> newstockbase)
        {
            foreach (StockInfoDyns stockBase in newstockbase)
            {
                SendPutThrough(stockBase);
            }
        }

        public void SendToQueue(string msg)
        {
            SendToQueue(msg, _queue);
        }

        #region Private functions & properties 


        protected void SendToQueue(string msg, CommunicationDataQueue queue)
        {
            _log.Info("Send To VData: " + msg);
            queue.SendStringToQueue(msg);
        }

        #endregion

    }
}
